// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Talina Gaming System (TgS) (∂)
//  »File«      TgS (XB2) Common - Math API [Vector] [F32].inl
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
// ------------------------------------------------------------------------------------------------------------------------------ //
//  Copyright: © 2002-2010, Andrew Aye.  All Rights Reserved.
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
#if !defined(_TGS_XB2_COMMON_MATH_API_VECTOR_F32_INL_)
#define _TGS_XB2_COMMON_MATH_API_VECTOR_F32_INL_
#pragma once


// START TGS - MATH ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

TgINLINE TgVEC_F32_04 M_TgVECTOR<TgFLOAT32,4>( const __vector4 vNative )
{
    register TgVEC_F32_04 tvResult;
    tvResult.m_mData = vNative;
    return (tvResult);
}


TgINLINE TgVEC_F32_04 M_SET4( C_TgFLOAT32 fX, C_TgFLOAT32 fY, C_TgFLOAT32 fZ, C_TgFLOAT32 fW )
{
    __vector4 v0 = __vrlimi(__lvlx(&fX, 0), __lvlx(&fY, 0), 0x4, 3);
    __vector4 v1 = __vrlimi(__lvlx(&fZ, 0), __lvlx(&fW, 0), 0x4, 3);
    return (M_TgVECTOR<TgFLOAT32,4>( __vrlimi( v0, v1, 0x3, 2 ) ));
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Permutations
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

template <TgUINT32 uiPerm> TgVEC_F32_04 M_PERM( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vpermwi( tvLeft.m_mData, uiPerm ) ));
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Floating-Point Arithmetic Operations
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgINLINE TgVEC_F32_04 M_ADD( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vaddfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_MAD( M_TgVEC_F32_04 tvM0, M_TgVEC_F32_04 tvM1, M_TgVEC_F32_04 tvA0 )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmaddfp( tvM0.m_mData, tvM1.m_mData, tvA0.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_NMS( M_TgVEC_F32_04 tvM0, M_TgVEC_F32_04 tvM1, M_TgVEC_F32_04 tvA0 )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vnmsubfp( tvM0.m_mData, tvM1.m_mData, tvA0.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_DOT3( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmsum3fp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_DOT4( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmsum4fp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_MUL( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmulfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_DIV( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmulfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_SUB( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vsubfp( tvLeft.m_mData, tvRight.m_mData ) ));
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Floating-Point Calculations
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgINLINE TgVEC_F32_04 M_LSQ( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmsum4fp( tvLeft.m_mData, tvLeft.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_LEN( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vrefp( __vrsqrtefp( __vmsum4fp( tvLeft.m_mData, tvLeft.m_mData ) ) ) ));
}


TgINLINE TgVEC_F32_04 M_NEG( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vxor( TgVEC04_MASK::mSgnM.m_u32_v04.m_mData, tvLeft.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_SQRT( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vrefp( __vrsqrtefp( tvLeft.m_mData ) ) ));
}


TgINLINE TgVEC_F32_04 M_RSQRT( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vrsqrtefp( tvLeft.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_NORM( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmulfp( tvLeft.m_mData, __vrsqrtefp( __vmsum4fp( tvLeft.m_mData, tvLeft.m_mData ) ) ) ));
}


TgINLINE TgVEC_F32_04 M_NORM( PCU_TgVEC_F32_04 tvRet_Length, M_TgVEC_F32_04 tvLeft )
{
    const register __vector4            vL0 = __vrsqrtefp( __vmsum4fp( tvLeft.m_mData, tvLeft.m_mData ) );

    *tvRet_Length = M_TgVECTOR<TgFLOAT32,4>( __vrefp( vL0 ) );

    return (M_TgVECTOR<TgFLOAT32,4>( __vmulfp( tvLeft.m_mData, vL0 ) ));

}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Floating-Point Bounds
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgINLINE TgVEC_F32_04 M_FLR( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vrfim( tvLeft.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_CEL( M_TgVEC_F32_04 tvLeft )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vrfip( tvLeft.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_CLP( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvMin, M_TgVEC_F32_04 tvMax )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmaxfp( tvMin.m_mData, __vminfp( tvMax.m_mData, tvLeft.m_mData ) ) ));
}


TgINLINE TgVEC_F32_04 M_SAT( M_TgVEC_F32_04 tvLeft )
{
    return (M_CLP( tvLeft, TgVEC_F32_04_K::ZERO, TgVEC_F32_04_K::ONE ));
}


TgINLINE TgVEC_F32_04 M_MAX( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vmaxfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_MIN( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vminfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_IsNaN( M_TgVEC_F32_04 tvLeft )
{
    return (M_CMP_EQ( M_AND( tvLeft, TgVEC04_MASK::mNaN.m_f32_v04 ), TgVEC04_MASK::mNaN.m_f32_v04 ));
}


TgINLINE TgVEC_F32_04 M_InBND( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvBound )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vcmpequw( __vcmpbfp( tvLeft.m_mData, tvBound.m_mData ), __vspltisw( 0  ) ) ));
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Comparison Operators
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgINLINE TgVEC_F32_04 M_CMP_EQ( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vcmpeqfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_CMP_NE( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vxor( TgKV_FFFF.m_mData, __vcmpeqfp( tvLeft.m_mData, tvRight.m_mData ) ) ));
}


TgINLINE TgVEC_F32_04 M_CMP_GE( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vcmpgefp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_CMP_GT( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vcmpgtfp( tvLeft.m_mData, tvRight.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_CMP_LE( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vcmpgefp( tvRight.m_mData, tvLeft.m_mData ) ));
}


TgINLINE TgVEC_F32_04 M_CMP_LT( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    return (M_TgVECTOR<TgFLOAT32,4>( __vcmpgtfp( tvRight.m_mData, tvLeft.m_mData ) ));
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Homogeneous Calculations
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgINLINE TgVEC_F32_04 M_CX( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    const __vector4                     vX1 = __vpermwi(  tvLeft.m_mData, 0x63 );
    const __vector4                     vX2 = __vpermwi( tvRight.m_mData, 0x87 );
    const __vector4                     vX3 = __vpermwi(  tvLeft.m_mData, 0x87 );
    const __vector4                     vX4 = __vpermwi( tvRight.m_mData, 0x63 );

    return (M_TgVECTOR<TgFLOAT32,4>( __vnmsubfp( vX3, vX4, __vmulfp( vX1, vX2 ) ) ));
}


TgINLINE TgVEC_F32_04 M_UCX( M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    const __vector4                     vX1 = __vpermwi(  tvLeft.m_mData, 0x63 );
    const __vector4                     vX2 = __vpermwi( tvRight.m_mData, 0x87 );
    const __vector4                     vX3 = __vpermwi(  tvLeft.m_mData, 0x87 );
    const __vector4                     vX4 = __vpermwi( tvRight.m_mData, 0x63 );
    const __vector4                     vF0 = __vnmsubfp( vX3, vX4, __vmulfp( vX1, vX2 ) );
    const __vector4                     vT0 = __vmsum4fp( vF0, vF0 );
    const __vector4                     vL0 = __vrsqrtefp( vT0 );

    return (M_TgVECTOR<TgFLOAT32,4>( __vmulfp( vF0, vL0 ) ));
}


TgINLINE TgVEC_F32_04 M_UCX( PCU_TgVEC_F32_04 tvRet_Length, M_TgVEC_F32_04 tvLeft, M_TgVEC_F32_04 tvRight )
{
    const __vector4                     vX1 = __vpermwi(  tvLeft.m_mData, 0x63 );
    const __vector4                     vX2 = __vpermwi( tvRight.m_mData, 0x87 );
    const __vector4                     vX3 = __vpermwi(  tvLeft.m_mData, 0x87 );
    const __vector4                     vX4 = __vpermwi( tvRight.m_mData, 0x63 );
    const __vector4                     vF0 = __vnmsubfp( vX3, vX4, __vmulfp( vX1, vX2 ) );
    const __vector4                     vT0 = __vmsum4fp( vF0, vF0 );
    const __vector4                     vL0 = __vrsqrtefp( vT0 );

    *tvRet_Length = M_TgVECTOR<TgFLOAT32,4>( __vrefp( vL0 ) );

    return (M_TgVECTOR<TgFLOAT32,4>( __vmulfp( vF0, vL0 ) ));
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Homogeneous Functions and Basis
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

TgINLINE TgVEC_F32_04 M_SETP( C_TgFLOAT32 fX, C_TgFLOAT32 fY, C_TgFLOAT32 fZ )
{
    return (M_SET4( fX, fY, fZ, 1.0F ));
}


TgINLINE TgVEC_F32_04 M_SETV( C_TgFLOAT32 fX, C_TgFLOAT32 fY, C_TgFLOAT32 fZ )
{
    return (M_SET4( fX, fY, fZ, 0.0F ));
}


TgINLINE TgVEC_F32_04 M_SETP( M_TgVEC_F32_04 tvRight )
{
    return (M_OR( TgVEC_F32_04_K::UNIT_W, M_AND( tvRight, TgVEC04_MASK::mFFF0.m_f32_v04 ) ));
}


TgINLINE TgVEC_F32_04 M_SETV( M_TgVEC_F32_04 tvRight )
{
    return (M_AND( tvRight, TgVEC04_MASK::mFFF0.m_f32_v04 ));
}




// END MATH ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// END TGS /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif //  END  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////